原文:https://stackoverflow.com/que...我的微信公众号:python每日一练
要理解什么是 yield
,必须理解什么是生成器(generator)。在理解生成器之前,让我们先了解迭代。
迭代
当你建立了一个列表,你可以逐个地访问这个列表的元素,而这个访问的过程叫做迭代(iteration)
>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
1
2
3
代码中的mylist
就是一个可迭代对象(iterable),当你使用列表生成式时,你就创建了一个list
,同时也创建了一个可迭代对象:
>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
... print(i)
0
1
4
凡是能使用for...in...
语句的对象,都叫做可迭代对象,例如:list
、string
、文件等等
这些可迭代对象非常方便,因为你可以根据自己的需要来访问它们。但是同时也需要将所有的值存入内存当中,无论你是不是需要所有的值,可能对于一个列表[x for x in range(100000)]
,你仅仅想拿到里面的素数,但当这个列表生成式被执行的时候,已经将所有100000个数字存入了内存中。
生成器
生成器是一种只能迭代一次的迭代器,生成器不会一次将所有的元素存入内存中,而是一边迭代一边运算:
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print(i)
0
1
4
这份代码看起来和上面的代码没有什么区别。但是你不能再次执行for i in mygenerator
,因为生成器只能使用一次:
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print(i)
...
0
1
4
>>> for i in mygenerator:
... print(i)
...
>>>
Yield
yield
的使用和return
的使用没什么区别,只是yield
会返回一个生成器
>>> def createGenerator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator = createGenerator() # 创建一个生成器
>>> print(mygenerator) # mygenerator是一个对象!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
... print(i)
0
1
4
当你的函数需要返回一个很大的元素集合,并且每个元素只需要用到一次的时候,使用yield
会非常方便
要想理解yield
,你必须理解当你调用一个包含yield
的函数的时候,函数体代码并不会执行,这个函数仅仅是返回一个生成器而已
>>> def createGenerator():
... print('head')
... for i in range(5):
... yield i*i
... print('tail')
...
>>> createGenerator()
<generator object createGenerator at 0x0000023454FB5990>
当你第一次向后迭代(用next
或for...in...
语句时)这个生成器时,函数体才会从最开始执行到yield
处然后返回yield
的值,随后再次向后迭代,会执行剩余的代码然后再次遇到yield
停止并返回值。直到运行到函数结尾处停止,此时如果是用next()
则会抛出StopIteration
异常,如果是用for...in...
则会结束循环并且不会有异常
>>> def createGenerator():
... print('head')
... for i in range(5):
... yield i*i
... print('tail')
...
>>> g = createGenerator()
>>> next(g)
head
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
tail
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。